package com.house365.arequest.utils;

import android.content.Context;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.widget.Toast;

import com.house365.arequest.components.RxActivity;
import com.house365.arequest.components.support.RxAppCompatActivity;
import com.house365.arequest.components.support.RxAppCompatDialogFragment;
import com.house365.arequest.components.support.RxDialogFragment;
import com.house365.arequest.components.support.RxFragment;
import com.house365.arequest.components.support.RxFragmentActivity;
import com.house365.arequest.error.ErrorParse;
import com.house365.arequest.listener.OnRxFailListener;
import com.trello.rxlifecycle3.RxLifecycle;
import com.trello.rxlifecycle3.android.ActivityEvent;
import com.trello.rxlifecycle3.android.FragmentEvent;

import io.reactivex.Observable;
import io.reactivex.ObservableTransformer;
import io.reactivex.android.schedulers.AndroidSchedulers;

/**
 * @author Arvin
 */
public class ARequestUtil {

    /**
     * 1，把请求结果返回到主线程
     * 2，绑定到页面的生命周期，在onDestroy时，不再接收请求返回
     * 3，拦截请求和解析过程中出现的异常，该异常会被拦截，请处理
     * 4，把请求和解析过程中出现的异常，解析后回调到界面
     * 墙裂推荐，fail和Error都会通过onerror返回,如果你在activity中，你可以调用lifecycle()方法，传入生命周期
     *
     * @param life             在Activity、Fragment中发起请求时，会绑定页面的生命周期，当界面Destroy时，请求就终止，不会再返回
     * @param flag             在回调方法中，你需要通过flag来判断是哪个请求的错误
     * @param onRxFailListener
     * @param <T>
     * @return
     */
    public static <T> ObservableTransformer<T, T> asyncWithErrorByActivity(Observable<ActivityEvent> life, int flag, OnRxFailListener onRxFailListener) {
        return upstream -> upstream.compose(asyncByActivity(life))
                .doOnError(throwable -> {
                    if (onRxFailListener != null)
                        onRxFailListener.onRxError(flag, ErrorParse.parseError(throwable));

                }).onErrorResumeNext(Observable.empty());
    }

    public static <T> ObservableTransformer<T, T> asyncWithError(Observable<FragmentEvent> life, int flag, OnRxFailListener onRxFailListener) {
        return upstream -> upstream.compose(asyncByFragment(life))
                .doOnError(throwable -> {
                    if (onRxFailListener != null)
                        onRxFailListener.onRxError(flag, ErrorParse.parseError(throwable));

                }).onErrorResumeNext(Observable.empty());
    }

    /**
     * 只关心正确的结果，不关心错误的结果
     *
     * @param life
     * @param <T>
     * @return
     */
    public static <T> ObservableTransformer<T, T> asyncWithErrorByActivity(Observable<ActivityEvent> life) {
        return asyncWithErrorByActivity(life, -1, null);
    }

    /**
     * 只关心正确的结果，不关心错误的结果
     *
     * @param life
     * @param <T>
     * @return
     */
    public static <T> ObservableTransformer<T, T> asyncWithError(Observable<FragmentEvent> life) {
        return asyncWithError(life, -1, null);
    }


    /**
     * 当你在adapter，或者view中进行请求的时候，你可以吧你能获取到的content传过来，此处会判断context能不能绑定生命周期
     * <p>
     * 1，把请求结果返回到主线程
     * 2，绑定到页面的生命周期，在onDestroy时，不再接收请求返回
     * 3，拦截请求和解析过程中出现的异常，该异常会被拦截，请处理
     * 4，把请求和解析过程中出现的异常，解析后回调到界面
     *
     * @param context          传入你能获取到的context，如果可以绑定生命周期则绑定
     * @param flag
     * @param onRxFailListener
     * @param <T>
     * @return
     */
    public static <T> ObservableTransformer<T, T> asyncWithError(Context context, int flag, OnRxFailListener onRxFailListener) {
        return upstream -> upstream.compose(asyncContext(context))
                .doOnError(throwable -> {
                    if (onRxFailListener != null)
                        onRxFailListener.onRxError(flag, ErrorParse.parseError(throwable));

                }).onErrorResumeNext(Observable.empty());
    }

    /**
     * 当你在adapter，或者view中进行请求的时候，你可以吧你能获取到的fragment传过来，此处会判断fragment能不能绑定生命周期
     * 1，把请求结果返回到主线程
     * 2，绑定到页面的生命周期，在onDestroy时，不再接收请求返回
     * 3，拦截请求和解析过程中出现的异常，该异常会被拦截，请处理
     * 4，把请求和解析过程中出现的异常，解析后回调到界面
     *
     * @param fragment         传入你能获取到的context，如果可以绑定生命周期则绑定
     * @param flag
     * @param onRxFailListener
     * @param <T>
     * @return
     */
    public static <T> ObservableTransformer<T, T> asyncWithError(Fragment fragment, int flag, OnRxFailListener onRxFailListener) {
        return upstream -> upstream.compose(asyncFragment(fragment))
                .doOnError(throwable -> {
                    if (onRxFailListener != null)
                        onRxFailListener.onRxError(flag, ErrorParse.parseError(throwable));

                }).onErrorResumeNext(Observable.empty());
    }


    /**
     * 请求，并不绑定如何生命周期
     * 1，把请求结果返回到主线程
     * 2，拦截请求和解析过程中出现的异常，该异常会被拦截，请处理
     * 3，把请求和解析过程中出现的异常，解析后回调到界面
     *
     * @param flag
     * @param onRxFailListener
     * @param <T>
     * @return
     */
    public static <T> ObservableTransformer<T, T> asyncWithError(int flag, OnRxFailListener onRxFailListener) {
        return upstream -> upstream.compose(asyncContext(null))
                .doOnError(throwable -> {
                    if (onRxFailListener != null)
                        onRxFailListener.onRxError(flag, ErrorParse.parseError(throwable));

                }).onErrorResumeNext(Observable.empty());
    }


    /**
     * 吧请求结果返回到主线程，并绑定生命周期
     * 异步请求，结果返回主线程
     * 需要自行处理onError，否则就会报错
     *
     * @param life
     * @param <T>
     * @return
     */
    private static <T> ObservableTransformer<T, T> asyncByActivity(Observable<ActivityEvent> life) {
        return upstream -> upstream.observeOn(AndroidSchedulers.mainThread())
                .compose(RxLifecycle.bindUntilEvent(life, ActivityEvent.DESTROY));
    }

    private static <T> ObservableTransformer<T, T> asyncByFragment(Observable<FragmentEvent> life) {
        return upstream -> upstream.observeOn(AndroidSchedulers.mainThread())
                .compose(RxLifecycle.bindUntilEvent(life, FragmentEvent.DESTROY_VIEW));
    }


    /**
     * 判断content是否可以绑定其生命周期，如果可以则绑定，否则忽略
     *
     * @param <T>
     * @return
     */
    private static <T> ObservableTransformer<T, T> asyncContext(Context context) {
        if (context instanceof RxAppCompatActivity)
            return asyncByActivity(((RxAppCompatActivity) context).lifecycle());
        if (context instanceof RxFragmentActivity)
            return asyncByActivity(((RxFragmentActivity) context).lifecycle());
        if (context instanceof RxActivity)
            return asyncByActivity(((RxActivity) context).lifecycle());
        return upstream -> upstream.observeOn(AndroidSchedulers.mainThread());
    }


    /**
     * 判断fragment是否可以绑定其生命周期，如果可以则绑定，否则忽略
     *
     * @param <T>
     * @return
     */
    private static <T> ObservableTransformer<T, T> asyncFragment(Fragment fragment) {
        if (fragment instanceof RxFragment)
            return asyncByFragment(((RxFragment) fragment).lifecycle());
        if (fragment instanceof RxAppCompatDialogFragment)
            return asyncByFragment(((RxAppCompatDialogFragment) fragment).lifecycle());
        if (fragment instanceof RxDialogFragment)
            return asyncByFragment(((RxDialogFragment) fragment).lifecycle());
        return upstream -> upstream.observeOn(AndroidSchedulers.mainThread());
    }


}
